// Copyright (c) Microsoft Corporation 2005-2007.
// This sample code is provided "as is" without warranty of any kind. 
// We disclaim all warranties, either express or implied, including the 
// warranties of merchantability and fitness for a particular purpose. 
//

#light

namespace Microsoft.FSharp.Linq

module SequenceOps = 

    open System
    open System.Linq
    open System.Data
    open System.Collections.Generic


    [<ReflectedDefinition>]
    let it x = x

    [<ReflectedDefinition>]
    let select f coll = 
        System.Linq.Enumerable.Select(coll,new Func<_,_>(f))

    [<ReflectedDefinition>]
    let selecti f (coll : #seq<_>) = 
        System.Linq.Enumerable.Select(coll,new Func<_,_,_>(f))

    [<ReflectedDefinition>]
    let selectMany f (coll : #seq<_>) = 
        System.Linq.Enumerable.SelectMany(coll,new Func<_,_>(f))

    [<ReflectedDefinition>]
    let selectManyi f (coll : #seq<_>) = 
        System.Linq.Enumerable.SelectMany(coll,new Func<_,_,_>(f))

    [<ReflectedDefinition>]
    let where f (coll : #seq<_>) = 
        System.Linq.Enumerable.Where(coll,new Func<_,_>(f))

    [<ReflectedDefinition>]
    let fmin<'a,'c,.. > (qf : ('a -> 'c)) (coll : #seq<'a>)  = 
        System.Linq.Enumerable.Min(coll,new Func<'a,'c>(qf))

    [<ReflectedDefinition>]
    let wherei f (coll : #seq<_>) = 
        System.Linq.Enumerable.Where(coll,new Func<_,int,_>(f))

    [<ReflectedDefinition>]
    let hd (coll : #seq<_>) = 
        System.Linq.Enumerable.First(coll)

    [<ReflectedDefinition>]
    let first f (coll : #seq<_>) = 
        System.Linq.Enumerable.First(coll,new Func<_,_>(f))

    [<ReflectedDefinition>]
    let count (coll : #seq<_>) = 
        System.Linq.Enumerable.Count(coll)

    [<ReflectedDefinition>]
    let defaultIfEmpty (coll : #seq<_>) = 
        System.Linq.Enumerable.DefaultIfEmpty(coll)

    [<ReflectedDefinition>]
    let distinct (coll : #seq<_>) = 
        System.Linq.Enumerable.Distinct(coll)

    [<ReflectedDefinition>]
    let firstOrDefault f (coll : #seq<_>) = 
        System.Linq.Enumerable.FirstOrDefault(coll, new Func<_,_>(f))

    [<ReflectedDefinition>]
    let seqmax f (coll : #seq<_>) = 
        System.Linq.Enumerable.Max<_,_>(coll, new Func<_,_>(f))

    [<ReflectedDefinition>]
    let seqmin f (coll : #seq<_>) = 
        System.Linq.Enumerable.Min<_,_>(coll, new Func<_,_>(f))

    [<ReflectedDefinition>]
    let union (first : #seq<_>) (second: #seq<_>) = 
        System.Linq.Enumerable.Union(first, second)

    [<ReflectedDefinition>]
    let intersect (first : #seq<_>) (second: #seq<_>) = 
        System.Linq.Enumerable.Intersect(first, second)

    let to_List (coll : #seq<_>) = 
        System.Linq.Enumerable.ToList(coll)

    let to_list coll = List.of_ResizeArray(to_List coll)

    let to_Array (coll : #seq<_>) = 
        System.Linq.Enumerable.ToArray(coll)

    let to_Dictionary keyf elemf (coll : #seq<_>) = 
        System.Linq.Enumerable.ToDictionary(coll,new Func<_,_>(keyf),new Func<_,_>(elemf))

    let iter f (coll : #seq<_>) = 
        Seq.iter f coll 

    [<ReflectedDefinition>]
    let square ((coll1 : #seq<_>), (coll2 : #seq<_>)) = 
        System.Linq.Enumerable.SelectMany(coll1, fun x -> coll2 |> select (fun y -> (x,y)))

    [<ReflectedDefinition>]
    let squarei ((coll1 : #seq<_>), (coll2 : #seq<_>)) = 
        System.Linq.Enumerable.SelectMany(coll1, fun x i -> coll2 |> selecti (fun y j -> (x,i,y,j)))

    [<ReflectedDefinition>]
    let take n (coll : #seq<_>) = 
        System.Linq.Enumerable.Take(coll, n)

    // "for outerElem in outerQuery
    //  join innerElem in innerQuery on OuterKeySelector[outerElem] equals InnerKeySelector[innerElem] into innerJoinResult
    //  remainingQuery"
    // ---> 
    // "->> groupJoin outerQuery innerQuery (fun outerElem -> OuterKeySelector) (fun innerElem -> InnerKeySelector) (fun outerElem innerJoinResult -> [| translate remainingQuery |]"
    [<ReflectedDefinition>]
    let groupJoin 
            (outer : #seq<'a>)  
            (inner : #seq<'b>) 
            (outerKeySelector : ('a -> 'key)) 
            (innerKeySelector : ('b -> 'key)) 
            (resultSelector : 'a -> seq<'b> -> 'c) : seq<'c> = 
        System.Linq.Enumerable.GroupJoin(outer,inner,new Func<_,_>(outerKeySelector),new Func<_,_>(innerKeySelector),new Func<_,_,_>(resultSelector))

    [<ReflectedDefinition>]
    let groupBy f (coll : #seq<_>) = 
        System.Linq.Enumerable.GroupBy(coll,new Func<_,_>(f))

    [<ReflectedDefinition>]
    let groupByAndProject f1 f2 (coll : #seq<_>) =
      System.Linq.Enumerable.GroupBy(coll,new Func<_,_>(f1), new Func<_,_>(f2))

    [<ReflectedDefinition>]
    let orderBy f (coll : #seq<_>) = 
        System.Linq.Enumerable.OrderBy(coll,new Func<_,_>(f))



